{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# TensorFlow Tutorial #12\n",
    "# Adversarial Noise for MNIST\n",
    "\n",
    "by [Magnus Erik Hvass Pedersen](http://www.hvass-labs.org/)/[GitHub中文](https://github.com/Hvass-Labs/TensorFlow-Tutorials-Chinese)\n",
    "/ [GitHub](https://github.com/Hvass-Labs/TensorFlow-Tutorials) / [Videos on YouTube](https://www.youtube.com/playlist?list=PL9Hr9sNUjfsmEu1ZniY0XpHSzl5uihcXZ)\n",
    "\n",
    "中文翻译 [thrillerist](https://zhuanlan.zhihu.com/insight-pixel)修订[ZhouGeorge](https://github.com/ZhouGeorge) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 介绍\n",
    "\n",
    "之前的教程#11展示了如何找到最先进神经网络的对抗样本，它会引起网络误分类图像，即使在人眼看来图像完全相同。例如，在添加了对抗噪声之后，一张鹦鹉的图像会被误分类成书架，但在人类眼中图像完全没什么变化。\n",
    "\n",
    "教程#11是通过每张图像的优化过程来寻找对抗噪声的。由于噪声是专门为某张图像生成，因此它可能不是通用的，无法在其他图像上起作用。\n",
    "\n",
    "本教程将会找到那些导致几乎所有输入图像都被误分类成目标类别的对抗噪声。我们使用MNIST手写数字数据集为例。现在，对抗噪声对人眼是清晰可见的，但人类还是能够很容易地辨认出数字，然而神经网络几乎将所有图像误分类。\n",
    "\n",
    "这篇教程里，我们还会试着让神经网络对对抗噪声免疫。\n",
    "\n",
    "教程 #11 用Numpy来做对抗优化。在这篇教程里，我们会直接在TensorFlow里实现优化过程。这会更快速，尤其是在使用GPU的时候，因为不用每次迭代都在GPU里拷贝数据。\n",
    "\n",
    "推荐你先学习教程 #11。你也需要大概地熟悉神经网络，详见教程 #01和 #02。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 流程图"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面的图表直接展示了之后实现的卷积神经网络中数据的传递。\n",
    "\n",
    "![Flowchart](images/12_adversarial_noise_flowchart.png)\n",
    "\n",
    "例子展示的是数字7的输入图像。随后在图像上添加对抗噪声。红色的噪声点是正值，它让像素值更深，蓝色噪声点是负值，让输入图像在此处的颜色更浅。\n",
    "\n",
    "这些噪声图像传到神经网络中，然后得到一个预测数字。这种情况下，对抗噪声让神经网络相信这张数字7的图像显示的是数字3。噪声对人眼是清晰可见的，但人类仍然可以容易地辨认出数字7来。\n",
    "\n",
    "这边值得注意的是，单一的噪声模式会导致神经网络将几乎所有的输入图像都误分类成期望的目标类型。\n",
    "\n",
    "在这个神经网络中有两个单独的优化程序。首先，我们优化神经网络的变量来分类训练集的图像。这是神经网络的常规优化过程。一旦分类准确率足够高，我们就切换到第二个优化程序，（它用来）寻找单一模式的对抗噪声，使得所有的输入图像都被误分类成目标类型。\n",
    "\n",
    "这两个优化程序是完全独立的。第一个程序只修改量神经网络的变量，第二个程序只修改对抗噪声。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 引导"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/magnus/anaconda3/envs/tf-gpu/lib/python3.6/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n",
      "  from ._conv import register_converters as _register_converters\n"
     ]
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "import tensorflow as tf\n",
    "import numpy as np\n",
    "from sklearn.metrics import confusion_matrix\n",
    "import time\n",
    "from datetime import timedelta\n",
    "import math"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用Python3.6（Anaconda）开发，TensorFlow版本是："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'1.9.0'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.__version__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 载入数据"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "MNIST数据集大约12MB，如果没在给定路径中找到就会自动下载。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from mnist import MNIST\n",
    "data = MNIST(data_dir=\"data/MNIST/\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在已经载入了MNIST数据集，它由70,000张图像和对应的标签（比如图像的类别）组成。数据集分成三份互相独立的子集。我们在教程中只用训练集和测试集。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Size of:\n",
      "- Training-set:\t\t55000\n",
      "- Validation-set:\t5000\n",
      "- Test-set:\t\t10000\n"
     ]
    }
   ],
   "source": [
    "print(\"Size of:\")\n",
    "print(\"- Training-set:\\t\\t{}\".format(data.num_train))\n",
    "print(\"- Validation-set:\\t{}\".format(data.num_val))\n",
    "print(\"- Test-set:\\t\\t{}\".format(data.num_test))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "为了方便起见，复制一些数据的维度。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# The number of pixels in each dimension of an image.\n",
    "img_size = data.img_size\n",
    "\n",
    "# The images are stored in one-dimensional arrays of this length.\n",
    "img_size_flat = data.img_size_flat\n",
    "\n",
    "# Tuple with height and width of images used to reshape arrays.\n",
    "img_shape = data.img_shape\n",
    "\n",
    "# Number of classes, one class for each of 10 digits.\n",
    "num_classes = data.num_classes\n",
    "\n",
    "# Number of colour channels for the images: 1 channel for gray-scale.\n",
    "num_channels = data.num_channels"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 用来绘制图像的帮助函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个函数用来在3x3的栅格中画9张图像，然后在每张图像下面写出真实类别和预测类别。如果提供了噪声，就将其添加到所有图像上。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_images(images, cls_true, cls_pred=None, noise=0.0):\n",
    "    assert len(images) == len(cls_true) == 9\n",
    "    \n",
    "    # Create figure with 3x3 sub-plots.\n",
    "    fig, axes = plt.subplots(3, 3)\n",
    "    fig.subplots_adjust(hspace=0.3, wspace=0.3)\n",
    "\n",
    "    for i, ax in enumerate(axes.flat):\n",
    "        # Get the i'th image and reshape the array.\n",
    "        image = images[i].reshape(img_shape)\n",
    "        \n",
    "        # Add the adversarial noise to the image.\n",
    "        image += noise\n",
    "        \n",
    "        # Ensure the noisy pixel-values are between 0 and 1.\n",
    "        image = np.clip(image, 0.0, 1.0)\n",
    "\n",
    "        # Plot image.\n",
    "        ax.imshow(image,\n",
    "                  cmap='binary', interpolation='nearest')\n",
    "\n",
    "        # Show true and predicted classes.\n",
    "        if cls_pred is None:\n",
    "            xlabel = \"True: {0}\".format(cls_true[i])\n",
    "        else:\n",
    "            xlabel = \"True: {0}, Pred: {1}\".format(cls_true[i], cls_pred[i])\n",
    "\n",
    "        # Show the classes as the label on the x-axis.\n",
    "        ax.set_xlabel(xlabel)\n",
    "        \n",
    "        # Remove ticks from the plot.\n",
    "        ax.set_xticks([])\n",
    "        ax.set_yticks([])\n",
    "    \n",
    "    # Ensure the plot is shown correctly with multiple plots\n",
    "    # in a single Notebook cell.\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 绘制几张图像来看看数据是否正确"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAUMAAAD5CAYAAAC9FVegAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAHihJREFUeJzt3XmUFNXZx/HvA0LYVQQFFWdOwAVCFBWDu0aBKCogccG4EGM0osEtAaNx1xglKBzRE7YD4QQNigKCUVFAEV8EJIIi4wYiCsRlhLggIsJ9/5i5XdUzPXtXVU/7+5zjmequ6qpnvPSdp27dxZxziIj80DVIOgARkVygylBEBFWGIiKAKkMREUCVoYgIoMpQRARQZSgiAqgyFBEBVBmKiACwS00ObtOmjSssLIwolNzzwQcfUFxcbEnHESeVcf5TGWdWo8qwsLCQZcuW1T6qeqZ79+5JhxA7lXH+UxlnpttkERFUGYqIAKoMRUQAVYYiIoAqQxERoIZPk0Vqa8SIEQBs3boVgDfeeAOAxx9/vNyxgwcPBuCoo44C4MILL4wjRPmBU2YoIoIyQ4nYueeeC8C0adMy7jcr3xd2zJgxAMydOxeAE044AYD99tsvihAlQe+++y4ABx54IAAPPPAAAEOGDIk9FmWGIiIoM5QI+GwQKs4IDzroIABOOeUUAN5///3UvlmzZgGwevVqAKZMmQLAjTfemP1gJVHLly8HoEGDkrxsn332SSwWZYYiIigzlCzy411nzJhRbl/Xrl2BIOtr06YNAC1atADgu+++Sx3bo0cPAF5//XUAPv/884gilqStWLECCP4dDBgwILFYlBmKiBBDZuj7kY0fPx6AvffeO7WvSZMmAJx//vkAtGvXDoBOnTpFHZZE4L///S8AzrnUez4jnDNnDgDt27fP+FnfDxHgrbfeStt3+umnZzVOSd7KlSsBGD16NAAXXXRRkuEAygxFRIAYMsOhQ4cCJRMsVsT3K2vVqhUAXbp0ycq1O3ToAMCwYcOAH+bcdXE644wzgOApMEDLli0BaN26daWfffTRR1Pb4fZDyU/vvPMOAFu2bAHSeyAkRZmhiAiqDEVEgBhukydMmAAE3STCt8BFRUVA0PHyxRdfBGDx4sVAMPzqww8/rPD8jRo1AoKuGr4RP3wef7us2+R4FBQUVPvYv/3tb0AwLCvMd7HxPyV/DB8+HChZggBy47upzFBEhBgyw5NPPjntZ5gfiuVt3rwZCDJF/9fi1VdfrfD8P/rRj4BgoLcf5gWwadMmADp27Fir2CU6Tz31FAC33HILANu2bUvt22uvvQC45557AGjWrFnM0UkUwg9R/Xfaf2+bN2+eREhplBmKiJBjw/F23313AE466aS09zNllWU98cQTQJBdAhx88MEADBw4MFshSpb4oXvhjNDz3Sz81F2SHxYsWFDuvbZt2yYQSWbKDEVEyLHMsDY+/fRTAK644gogfSiYb4+qqsOvxKd///5AMDzPGzRoUGr7rrvuijUmiYdf6iHMD4jIBcoMRUTIg8zwoYceAoIMcbfddkvt80+qJHm+/+eiRYuAoK3QtxnddNNNqWP9dE6SH1555RUAJk2alHrv0EMPBaBXr16JxJSJMkMREepxZvjyyy8DQV8078knn0xt++mjJHl+0s7i4uK09/30beoLmr/mzZsHpPf08H2M/TR+uUCZoYgIqgxFRIB6fJv89NNPA8Hcdz179gTgqKOOSiwmKc+veeKHWHonnngiAHfccUfcIUnM/CQtYWeffXYCkVROmaGICPUwM9y6dSsAzz77LBBM1HD77bcDwZRekpzwanZ33303UH726m7dugHqRpPPPv74YwAWLlwIpE+icuaZZyYSU2WUGYqIUA8zQz8ZqG+DOvXUUwE4+uijE4tJ0t13332p7aVLl6bt88Px1FaY//7xj38A8MknnwDBdzVXKTMUEaGeZIZ+IlCAO++8E4Bdd90VgJtvvjmRmKRi999/f4X7/PBJtRXmv3Xr1qW99lP05SplhiIi5Hhm6J9KXnXVVan3vv/+ewD69OkDqF9hfePLtDpP/X3274/dvn07AF988UW5Y/1Qr5EjR2Y8V8OGDVPb9957L6DlBKI2e/bstNenn356QpFUjzJDERFUGYqIADl6m7xjxw4gmNli7dq1qX2dOnUCggcpUr/4dWmq45xzzgGgffv2QNBFY+rUqXWKwa++F55DUbLHd7L25VVfKDMUESFHM8M1a9YAwQpqYb7bhua/y13+4RbAzJkza32exx57rMpj/MOVBg3S/6737dsXCNbeDjv22GNrHZNUbcaMGUDwsNPPap3rqx0qMxQRIccyQ99Js3fv3mnvjxgxIrWd64/nBaZPn57aHj58OFB+ogavqKgIqLwd8JJLLgGgoKCg3L5f/vKXAHTu3Ll2wUrWfPPNNwA888wzae/76brC3ZtykTJDERFyLDMcO3YsUH4Y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e27WriPV47ODa6+9FgjuEMzS59ocMmRIavvBBx8EoHXr1nGEKLXgyxGCzO/YY48Fgt4ajRs3BmDXXXcFoEWLFqnPfP311wD84he/AIKsr0ePHgAceuihqWObNm0KQPPmzbP8W6RTZigigipDEREghttk37H6iSeeKLdv4sSJALRt27bO1/G3x7169Sq3b8CAAQC0bNmyzteRmvFNFf5hWUWmTp2a2n7mmWeA4GGLv4X2t12SnC1btgDp37PXX38dgJkzZ6Yde9RRRwGwfPlyIL3LnH+Atu+++wLQoEHyeVnyEYiI5IDIM8M//OEPQNC1wneABjj77LOzdp2XX34ZgI8//jj13sUXXwzABRdckLXrSNXWrVuX2p40aVLaPj+Y3newf/7558t93neW91nl+eefD0C7du2yH6xUy3fffQfAr371KyDIBgFuvPFGAHr27Jnxs5kGUey3335ZjrDulBmKiBBDZui7UPif++yzT2pfXdqA/HCeu+++GwiG/IS7bPg2SYnXihUrUtu+M/Xxxx8PwIIFCwD49ttvAXjkkUcA+Otf/5r6zOrVq4Egy+/Xrx8QtCWqy018fBcY/z3zEyuE2/mHDh0KQLNmzWKOLruUGYqIkMBEDX7qHoDevXsDsNtuuwEwePDgKj/vO237n4sXL07bn812SKmd8NRKPlP3na69Jk2aAPCb3/wGgMcffzy1zw/w94P4fcahp8nx80+I77nnHiCYYHXhwoWpY3yn6vpOmaGICDFkhldffTUA8+fPB2Djxo2pfb79yGcATz75ZJXn88eWHc7VsWNHIGjbkOT861//Kvfev//9bwD69++f8TN+WrVMjjzySCB9OJfEY9GiRWmv/TA53z8wnygzFBEhhszw8MMPB2DlypVA+pPGZ599FoDhw4cDsOeeewIwaNCgCs934YUXAnDwwQenve+XDPAZoiTnvPPOS237bP/VV18F4O233waCfw8zZswA0if99W3I/j0/9Zov+y5dukQWu6QLt+VC8ET/9ttvT73Xt29fIH1yhfpImaGICKoMRUQAsJqsQdC9e3dXWUN3HN5//30guB3u1q0bAM899xyQnUkfvO7du7Ns2TKr+sj8kY0y3rRpU2rbl5MfYlfRA7DwwH/fgf70008H4N133wWCVRPHjBlTp/jCVMaVKztoIpOGDRsCcPnllwPBnIQfffQR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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f5e636b45f8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Get the first images from the test-set.\n",
    "images = data.x_test[0:9]\n",
    "\n",
    "# Get the true classes for those images.\n",
    "cls_true = data.y_test_cls[0:9]\n",
    "\n",
    "# Plot the images and labels using our helper-function above.\n",
    "plot_images(images=images, cls_true=cls_true)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## TensorFlow图（Graph）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在将使用TensorFlow和PrettyTensor构建神经网络的计算图。 与往常一样，我们需要为图像创建占位符变量，将其送到计算图中，然后将对抗噪声添加到图像中。接着把噪声图像用作卷积神经网络的输入。\n",
    "\n",
    "这个网络有两个单独的优化程序。神经网络本身变量的一个常规优化过程，以及对抗噪声的另一个优化过程。 两个优化过程都直接在TensorFlow中实现。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 占位符 （Placeholder）变量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "占位符变量为TensorFlow中的计算图提供了输入，我们可以在每次执行图的时候更改。 我们称为feeding占位符变量。\n",
    "\n",
    "首先，我们为输入图像定义占位符变量。 这允许我们改变输入到TensorFlow图中的图像。 这是一个张量，代表它是一个多维数组。 数据类型设为`float32`，形状设为`[None，img_size_flat]`，其中`None`代表张量可以保存任意数量的图像，每个图像是长度为`img_size_flat`的向量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = tf.placeholder(tf.float32, shape=[None, img_size_flat], name='x')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "卷积层希望`x`被编码为4维张量，因此我们需要将它的形状转换至`[num_images, img_height, img_width, num_channels]`。注意`img_height == img_width == img_size`，如果第一维的大小设为-1， num_images的大小也会被自动推导出来。转换运算如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_image = tf.reshape(x, [-1, img_size, img_size, num_channels])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "接下来我们为输入变量x中的图像所对应的真实标签定义占位符变量。变量的形状是`[None, num_classes]`，这代表着它保存了任意数量的标签，每个标签是长度为`num_classes`的向量，本例中长度为10。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_true = tf.placeholder(tf.float32, shape=[None, num_classes], name='y_true')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们也可以为类别号提供一个占位符，但这里用argmax来计算它。这里只是TensorFlow中的一些操作符，没有执行什么运算。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_true_cls = tf.argmax(y_true, axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 对抗噪声"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "输入图像的像素值在0.0到1.0之间。对抗噪声是在输入图像上添加或删除的数值。\n",
    "\n",
    "对抗噪声的界限设为0.35，则噪声在正负0.35之间。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "noise_limit = 0.35"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对抗噪声的优化器会试图最小化两个损失度量：(1)神经网络常规的损失度量，因此我们会找到使得目标类型分类准确率最高的噪声；(2)L2-loss度量，它会保持尽可能低的噪声。\n",
    "\n",
    "下面的权重决定了与常规的损失度量相比，L2-loss的重要性。通常接近零的L2权重表现的更好。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "noise_l2_weight = 0.02"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当我们为噪声创建变量时，必须告知TensorFlow它属于哪一个变量集合，这样，后面就能通知两个优化器要更新哪些变量。\n",
    "\n",
    "首先为变量集合定义一个名称。这只是一个字符串。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "ADVERSARY_VARIABLES = 'adversary_variables'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "接着，创建噪声变量所属集合的列表。如果我们将噪声变量添加到集合`tf.GraphKeys.VARIABLES`中，它就会和TensorFlow图中的其他变量一起被初始化，但不会被优化。这里有点混乱。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "collections = [tf.GraphKeys.GLOBAL_VARIABLES, ADVERSARY_VARIABLES]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在我们可以为对抗噪声添加新的变量。它会被初始化为零。它是不可训练的，因此并不会与神经网络中的其他变量一起被优化。这让我们可以创建两个独立的优化程序。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_noise = tf.Variable(tf.zeros([img_size, img_size, num_channels]),\n",
    "                      name='x_noise', trainable=False,\n",
    "                      collections=collections)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对抗噪声会被限制在我们上面设定的噪声界限内。注意此时并未在计算图表内进行计算，在优化步骤之后执行，详见下文。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_noise_clip = tf.assign(x_noise, tf.clip_by_value(x_noise,\n",
    "                                                   -noise_limit,\n",
    "                                                   noise_limit))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "噪声图像只是输入图像和对抗噪声的总和。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_noisy_image = x_image + x_noise"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "把噪声图像添加到输入图像上时，它可能会溢出有效图像（像素）的边界，因此我们裁剪/限制噪声图像，确保它的像素值在0到1之间。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_noisy_image = tf.clip_by_value(x_noisy_image, 0.0, 1.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 卷积神经网络"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我将使用Layers API 去构建神经网络，见教程 #03-B。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Start the network with the noisy input image.\n",
    "net = x_noisy_image\n",
    "\n",
    "# 1st convolutional layer.\n",
    "net = tf.layers.conv2d(inputs=net, name='layer_conv1', padding='same',\n",
    "                       filters=16, kernel_size=5, activation=tf.nn.relu)\n",
    "net = tf.layers.max_pooling2d(inputs=net, pool_size=2, strides=2)\n",
    "\n",
    "# 2nd convolutional layer.\n",
    "net = tf.layers.conv2d(inputs=net, name='layer_conv2', padding='same',\n",
    "                       filters=36, kernel_size=5, activation=tf.nn.relu)\n",
    "net = tf.layers.max_pooling2d(inputs=net, pool_size=2, strides=2)\n",
    "\n",
    "# Flatten layer.This should eventually be replaced by:\n",
    "# net = tf.layers.flatten(net)\n",
    "net = tf.contrib.layers.flatten(net)\n",
    "\n",
    "# 1st fully-connected / dense layer.\n",
    "net = tf.layers.dense(inputs=net, name='layer_fc1',\n",
    "                      units=128, activation=tf.nn.relu)\n",
    "\n",
    "# 2nd fully-connected / dense layer.\n",
    "net = tf.layers.dense(inputs=net, name='layer_fc_out',\n",
    "                      units=num_classes, activation=None)\n",
    "\n",
    "# Unscaled output of the network.\n",
    "logits = net\n",
    "\n",
    "# Softmax output of the network.\n",
    "y_pred = tf.nn.softmax(logits=logits)\n",
    "\n",
    "# Loss measure to be optimized.\n",
    "cross_entropy = tf.nn.softmax_cross_entropy_with_logits_v2(labels=y_true,\n",
    "                                                           logits=logits)\n",
    "loss = tf.reduce_mean(cross_entropy)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 正常训练的优化器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这是会在常规优化程序里被训练的神经网络的变量列表。注意，`'x_noise:0'`不在列表里，因此这个程序并不会优化对抗噪声。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['layer_conv1/kernel:0',\n",
       " 'layer_conv1/bias:0',\n",
       " 'layer_conv2/kernel:0',\n",
       " 'layer_conv2/bias:0',\n",
       " 'layer_fc1/kernel:0',\n",
       " 'layer_fc1/bias:0',\n",
       " 'layer_fc_out/kernel:0',\n",
       " 'layer_fc_out/bias:0']"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[var.name for var in tf.trainable_variables()]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "神经网络中这些变量的优化由Adam-optimizer完成，它用到上面PretyTensor构造的神经网络所返回的损失度量。\n",
    "\n",
    "此时不执行优化，实际上这里根本没有计算，我们只是把优化对象添加到TensorFlow图表中，以便稍后运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "optimizer = tf.train.AdamOptimizer(learning_rate=1e-4).minimize(loss)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 对抗噪声的优化器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "获取变量列表，这些是需要在第二个程序里为对抗噪声做优化的变量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "adversary_variables = tf.get_collection(ADVERSARY_VARIABLES)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "展示变量名称列表。这里只有一个元素，是我们在上面创建的对抗噪声变量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['x_noise:0']"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[var.name for var in adversary_variables]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们会将常规优化的损失函数与所谓的L2-loss相结合。这将会得到在最佳分类准确率下的最小对抗噪声。\n",
    "\n",
    "L2-loss由一个通常设置为接近零的权重缩放。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "l2_loss_noise = noise_l2_weight * tf.nn.l2_loss(x_noise)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "将正常的损失函数和对抗噪声的L2-loss相结合。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "loss_adversary = loss + l2_loss_noise"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在可以为对抗噪声创建优化器。由于优化器并不能更新神经网络的所有变量，我们必须给出一个需要更新的变量的列表，即对抗噪声变量。注意，这里的学习率比上面的常规优化器要大很多。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "optimizer_adversary = tf.train.AdamOptimizer(learning_rate=1e-2).minimize(loss_adversary, var_list=adversary_variables)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在我们为神经网络创建了两个优化器，一个用于神经网络的变量，另一个用于对抗噪声的单个变量。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 性能度量\n",
    "\n",
    "在TensorFlow图表中，我们需要另外一些操作，以便在优化过程中向用户展示进度。\n",
    "\n",
    "首先，计算出神经网络输出`y_pred`的预测类别号，它是一个包含10个元素的向量。类型号是最大元素的索引。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred_cls = tf.argmax(y_pred, axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "接着创建一个布尔数组，用来表示每张图像的预测类型是否与真实类型相同。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "correct_prediction = tf.equal(y_pred_cls, y_true_cls)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面的计算先将布尔值向量类型转换成浮点型向量，这样子False就变成0，True变成1，然后计算这些值的平均数，以此来计算分类的准确度。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 运行TensorFlow"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建TensorFlow会话（session）\n",
    "\n",
    "一旦创建了TensorFlow图，我们需要创建一个TensorFlow会话，用来运行图。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "session = tf.Session()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 初始化变量\n",
    "\n",
    "我们需要在开始优化`weights`和`biases`变量之前对它们进行初始化。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "session.run(tf.global_variables_initializer())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "帮助函数将对抗噪声初始化/重置为零。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "def init_noise():\n",
    "    session.run(tf.variables_initializer([x_noise]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "调用函数来初始化对抗噪声。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "init_noise()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 用来优化迭代的帮助函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在训练集中有55,000张图。用全部图像计算模型的梯度会花很多时间。因此我们在优化器的每次迭代里只用到了一小部分的图像。\n",
    "\n",
    "如果内存耗尽导致电脑死机或变得很慢，你应该试着减少这些数量，但同时可能还需要更优化的迭代。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_batch_size = 64"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面的函数用来执行一定数量的优化迭代，以此来逐渐改善神经网络的变量。在每次迭代中，会从训练集中选择新的一批数据，然后TensorFlow在这些训练样本上执行优化。每100次迭代会打印出进度。\n",
    "\n",
    "这个函数与之前教程中的相似，除了现在它多了一个对抗目标类别(adversary target-class)的参数。当目标类别设为整数时，将会用它取代训练集中的真实类别号。也会用对抗优化器代替常规优化器，然后在每次优化之后，噪声将被限制/截断到允许的范围。这里优化了对抗噪声，并忽略神经网络中的其他变量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "def optimize(num_iterations, adversary_target_cls=None):\n",
    "    # Start-time used for printing time-usage below.\n",
    "    start_time = time.time()\n",
    "\n",
    "    for i in range(num_iterations):\n",
    "\n",
    "        # Get a batch of training examples.\n",
    "        # x_batch now holds a batch of images and\n",
    "        # y_true_batch are the true labels for those images.\n",
    "        x_batch, y_true_batch, _ = data.random_batch(batch_size=train_batch_size)\n",
    "\n",
    "        # If we are searching for the adversarial noise, then\n",
    "        # use the adversarial target-class instead.\n",
    "        if adversary_target_cls is not None:\n",
    "            # The class-labels are One-Hot encoded.\n",
    "            \n",
    "            # Set all the class-labels to zero.\n",
    "            y_true_batch = np.zeros_like(y_true_batch)\n",
    "\n",
    "            # Set the element for the adversarial target-class to 1.\n",
    "            y_true_batch[:, adversary_target_cls] = 1.0\n",
    "            \n",
    "        # Put the batch into a dict with the proper names\n",
    "        # for placeholder variables in the TensorFlow graph.\n",
    "        feed_dict_train = {x: x_batch,\n",
    "                           y_true: y_true_batch}\n",
    "\n",
    "        # If doing normal optimization of the neural network.\n",
    "        if adversary_target_cls is None:\n",
    "            # Run the optimizer using this batch of training data.\n",
    "            # TensorFlow assigns the variables in feed_dict_train\n",
    "            # to the placeholder variables and then runs the optimizer.\n",
    "            session.run(optimizer, feed_dict=feed_dict_train)\n",
    "        else:\n",
    "            # Run the adversarial optimizer instead.\n",
    "            # Note that we have 'faked' the class above to be\n",
    "            # the adversarial target-class instead of the true class.\n",
    "            session.run(optimizer_adversary, feed_dict=feed_dict_train)\n",
    "            \n",
    "            # Clip / limit the adversarial noise. This executes\n",
    "            # another TensorFlow operation. It cannot be executed\n",
    "            # in the same session.run() as the optimizer, because\n",
    "            # it may run in parallel so the execution order is not\n",
    "            # guaranteed. We need the clip to run after the optimizer.\n",
    "            session.run(x_noise_clip)\n",
    "\n",
    "        # Print status every 100 iterations.\n",
    "        if (i % 100 == 0) or (i == num_iterations - 1):\n",
    "            # Calculate the accuracy on the training-set.\n",
    "            acc = session.run(accuracy, feed_dict=feed_dict_train)\n",
    "\n",
    "            # Message for printing.\n",
    "            msg = \"Optimization Iteration: {0:>6}, Training Accuracy: {1:>6.1%}\"\n",
    "\n",
    "            # Print it.\n",
    "            print(msg.format(i, acc))\n",
    "\n",
    "    # Ending time.\n",
    "    end_time = time.time()\n",
    "\n",
    "    # Difference between start and end-times.\n",
    "    time_dif = end_time - start_time\n",
    "\n",
    "    # Print the time-usage.\n",
    "    print(\"Time usage: \" + str(timedelta(seconds=int(round(time_dif)))))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 获取及绘制噪声的帮助函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个函数从TensorFlow图表中获取对抗噪声。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_noise():\n",
    "    # Run the TensorFlow session to retrieve the contents of\n",
    "    # the x_noise variable inside the graph.\n",
    "    noise = session.run(x_noise)\n",
    "\n",
    "    return np.squeeze(noise)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个函数绘制了对抗噪声，并打印一些统计信息。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_noise():\n",
    "    # Get the adversarial noise from inside the TensorFlow graph.\n",
    "    noise = get_noise()\n",
    "    \n",
    "    # Print statistics.\n",
    "    print(\"Noise:\")\n",
    "    print(\"- Min:\", noise.min())\n",
    "    print(\"- Max:\", noise.max())\n",
    "    print(\"- Std:\", noise.std())\n",
    "\n",
    "    # Plot the noise.\n",
    "    plt.imshow(noise, interpolation='nearest', cmap='seismic',\n",
    "               vmin=-1.0, vmax=1.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 用来绘制错误样本的帮助函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "函数用来绘制测试集中被误分类的样本。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_example_errors(cls_pred, correct):\n",
    "    # This function is called from print_test_accuracy() below.\n",
    "\n",
    "    # cls_pred is an array of the predicted class-number for\n",
    "    # all images in the test-set.\n",
    "\n",
    "    # correct is a boolean array whether the predicted class\n",
    "    # is equal to the true class for each image in the test-set.\n",
    "\n",
    "    # Negate the boolean array.\n",
    "    incorrect = (correct == False)\n",
    "    \n",
    "    # Get the images from the test-set that have been\n",
    "    # incorrectly classified.\n",
    "    images = data.x_test[incorrect]\n",
    "    \n",
    "    # Get the predicted classes for those images.\n",
    "    cls_pred = cls_pred[incorrect]\n",
    "\n",
    "    # Get the true classes for those images.\n",
    "    cls_true = data.y_test_cls[incorrect]\n",
    "\n",
    "    # Get the adversarial noise from inside the TensorFlow graph.\n",
    "    noise = get_noise()\n",
    "    \n",
    "    # Plot the first 9 images.\n",
    "    plot_images(images=images[0:9],\n",
    "                cls_true=cls_true[0:9],\n",
    "                cls_pred=cls_pred[0:9],\n",
    "                noise=noise)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 绘制混淆（confusion）矩阵的帮助函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_confusion_matrix(cls_pred):\n",
    "    # This is called from print_test_accuracy() below.\n",
    "\n",
    "    # cls_pred is an array of the predicted class-number for\n",
    "    # all images in the test-set.\n",
    "\n",
    "    # Get the true classifications for the test-set.\n",
    "    cls_true = data.y_test_cls\n",
    "    \n",
    "    # Get the confusion matrix using sklearn.\n",
    "    cm = confusion_matrix(y_true=cls_true,\n",
    "                          y_pred=cls_pred)\n",
    "\n",
    "    # Print the confusion matrix as text.\n",
    "    print(cm)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 展示性能的帮助函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "函数用来打印测试集上的分类准确度。\n",
    "\n",
    "为测试集上的所有图片计算分类会花费一段时间，因此我们直接用这个函数来调用上面的结果，这样就不用每次都重新计算了。\n",
    "\n",
    "这个函数可能会占用很多电脑内存，这也是为什么将测试集分成更小的几个部分。如果你的电脑内存比较小或死机了，就要试着降低batch-size。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Split the test-set into smaller batches of this size.\n",
    "test_batch_size = 256\n",
    "\n",
    "def print_test_accuracy(show_example_errors=False,\n",
    "                        show_confusion_matrix=False):\n",
    "\n",
    "    # Number of images in the test-set.\n",
    "    num_test = data.num_test\n",
    "\n",
    "    # Allocate an array for the predicted classes which\n",
    "    # will be calculated in batches and filled into this array.\n",
    "    cls_pred = np.zeros(shape=num_test, dtype=np.int)\n",
    "\n",
    "    # Now calculate the predicted classes for the batches.\n",
    "    # We will just iterate through all the batches.\n",
    "    # There might be a more clever and Pythonic way of doing this.\n",
    "\n",
    "    # The starting index for the next batch is denoted i.\n",
    "    i = 0\n",
    "\n",
    "    while i < num_test:\n",
    "        # The ending index for the next batch is denoted j.\n",
    "        j = min(i + test_batch_size, num_test)\n",
    "\n",
    "        # Get the images from the test-set between index i and j.\n",
    "        images = data.x_test[i:j, :]\n",
    "\n",
    "        # Get the associated labels.\n",
    "        labels = data.y_test[i:j, :]\n",
    "\n",
    "        # Create a feed-dict with these images and labels.\n",
    "        feed_dict = {x: images,\n",
    "                     y_true: labels}\n",
    "\n",
    "        # Calculate the predicted class using TensorFlow.\n",
    "        cls_pred[i:j] = session.run(y_pred_cls, feed_dict=feed_dict)\n",
    "\n",
    "        # Set the start-index for the next batch to the\n",
    "        # end-index of the current batch.\n",
    "        i = j\n",
    "\n",
    "    # Convenience variable for the true class-numbers of the test-set.\n",
    "    cls_true = data.y_test_cls\n",
    "\n",
    "    # Create a boolean array whether each image is correctly classified.\n",
    "    correct = (cls_true == cls_pred)\n",
    "\n",
    "    # Calculate the number of correctly classified images.\n",
    "    # When summing a boolean array, False means 0 and True means 1.\n",
    "    correct_sum = correct.sum()\n",
    "\n",
    "    # Classification accuracy is the number of correctly classified\n",
    "    # images divided by the total number of images in the test-set.\n",
    "    acc = float(correct_sum) / num_test\n",
    "\n",
    "    # Print the accuracy.\n",
    "    msg = \"Accuracy on Test-Set: {0:.1%} ({1} / {2})\"\n",
    "    print(msg.format(acc, correct_sum, num_test))\n",
    "\n",
    "    # Plot some examples of mis-classifications, if desired.\n",
    "    if show_example_errors:\n",
    "        print(\"Example errors:\")\n",
    "        plot_example_errors(cls_pred=cls_pred, correct=correct)\n",
    "\n",
    "    # Plot the confusion matrix, if desired.\n",
    "    if show_confusion_matrix:\n",
    "        print(\"Confusion Matrix:\")\n",
    "        plot_confusion_matrix(cls_pred=cls_pred)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 神经网络的常规优化\n",
    "\n",
    "此时对抗噪声还没有效果，因为上面只将它初始化为零，在优化过程中并未更新。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Optimization Iteration:      0, Training Accuracy:  20.3%\n",
      "Optimization Iteration:    100, Training Accuracy:  71.9%\n",
      "Optimization Iteration:    200, Training Accuracy:  90.6%\n",
      "Optimization Iteration:    300, Training Accuracy:  84.4%\n",
      "Optimization Iteration:    400, Training Accuracy:  87.5%\n",
      "Optimization Iteration:    500, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    600, Training Accuracy:  89.1%\n",
      "Optimization Iteration:    700, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    800, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    900, Training Accuracy:  90.6%\n",
      "Optimization Iteration:    999, Training Accuracy:  93.8%\n",
      "Time usage: 0:00:03\n"
     ]
    }
   ],
   "source": [
    "optimize(num_iterations=1000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "测试集上的分类准确率大约96-97%。（每次运行Python Notobook时，结果会有所变化。）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy on Test-Set: 94.2% (9417 / 10000)\n",
      "Example errors:\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f5e38074128>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "print_test_accuracy(show_example_errors=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 寻找对抗噪声"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在我们开始优化对抗噪声之前，先将它初始化为零。上面已经完成了这一步，但这里再执行一次，以防你用其他目标类型重新运行代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "init_noise()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在执行对抗噪声的优化。这里使用对抗优化器而不是常规优化器，这说明它只优化对抗噪声变量，同时忽略神经网络中的其他变量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Optimization Iteration:      0, Training Accuracy:   7.8%\n",
      "Optimization Iteration:    100, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    200, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    300, Training Accuracy:  98.4%\n",
      "Optimization Iteration:    400, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    500, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    600, Training Accuracy:  96.9%\n",
      "Optimization Iteration:    700, Training Accuracy:  96.9%\n",
      "Optimization Iteration:    800, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    900, Training Accuracy:  96.9%\n",
      "Optimization Iteration:    999, Training Accuracy:  92.2%\n",
      "Time usage: 0:00:02\n"
     ]
    }
   ],
   "source": [
    "optimize(num_iterations=1000, adversary_target_cls=3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在对抗噪声已经被优化了，可以在一张图像中展示出来。红色像素显示了正噪声值，蓝色像素显示了负噪声值。这个噪声模式将会被添加到每张输入图像中。正噪声值（红）使像素变暗，负噪声值（蓝）使像素变亮。如下所示。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Noise:\n",
      "- Min: -0.35\n",
      "- Max: 0.35\n",
      "- Std: 0.19540551\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f5e38070048>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_noise()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当测试集的所有图像上都添加了该噪声之后，根据选定的目标类别，分类准确率通常在是10-15%之间。我们也能从混淆矩阵中看出，测试集中的大多数图像都被分类成期望的目标类别——尽管有些目标类型比其他的需要更多的对抗噪声。\n",
    "\n",
    "所以我们找到了使对抗噪声，使神经网络将测试集中绝大部分图像误分类成期望的类别。\n",
    "\n",
    "我们也可以画出一些带有对抗噪声的误分类图像样本。噪声清晰可见，但人眼还是可以轻易地分辨出数字。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy on Test-Set: 13.8% (1378 / 10000)\n",
      "Example errors:\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f5db664b940>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Confusion Matrix:\n",
      "[[ 115    0    0  863    0    0    0    2    0    0]\n",
      " [   0    0    0 1135    0    0    0    0    0    0]\n",
      " [   0    0  146  886    0    0    0    0    0    0]\n",
      " [   0    0    0 1010    0    0    0    0    0    0]\n",
      " [   0    0    0  966   16    0    0    0    0    0]\n",
      " [   0    0    0  865    0   27    0    0    0    0]\n",
      " [   0    0    0  946    0    1   11    0    0    0]\n",
      " [   0    0    0  981    0    0    0   47    0    0]\n",
      " [   0    0    0  968    0    0    0    0    6    0]\n",
      " [   0    0    1 1008    0    0    0    0    0    0]]\n"
     ]
    }
   ],
   "source": [
    "print_test_accuracy(show_example_errors=True,\n",
    "                    show_confusion_matrix=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 所有目标类别的对抗噪声"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这是帮助函数用于寻找所有目标类别的对抗噪声。函数从类型号0遍历到9，执行上面的优化。然后将结果保存到一个数组中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "def find_all_noise(num_iterations=1000):\n",
    "    # Adversarial noise for all target-classes.\n",
    "    all_noise = []\n",
    "\n",
    "    # For each target-class.\n",
    "    for i in range(num_classes):\n",
    "        print(\"Finding adversarial noise for target-class:\", i)\n",
    "\n",
    "        # Reset the adversarial noise to zero.\n",
    "        init_noise()\n",
    "\n",
    "        # Optimize the adversarial noise.\n",
    "        optimize(num_iterations=num_iterations,\n",
    "                 adversary_target_cls=i)\n",
    "\n",
    "        # Get the adversarial noise from inside the TensorFlow graph.\n",
    "        noise = get_noise()\n",
    "\n",
    "        # Append the noise to the array.\n",
    "        all_noise.append(noise)\n",
    "\n",
    "        # Print newline.\n",
    "        print()\n",
    "    \n",
    "    return all_noise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Finding adversarial noise for target-class: 0\n",
      "Optimization Iteration:      0, Training Accuracy:   4.7%\n",
      "Optimization Iteration:    100, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    200, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    299, Training Accuracy:  89.1%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Finding adversarial noise for target-class: 1\n",
      "Optimization Iteration:      0, Training Accuracy:  14.1%\n",
      "Optimization Iteration:    100, Training Accuracy:  68.8%\n",
      "Optimization Iteration:    200, Training Accuracy:  67.2%\n",
      "Optimization Iteration:    299, Training Accuracy:  60.9%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Finding adversarial noise for target-class: 2\n",
      "Optimization Iteration:      0, Training Accuracy:   7.8%\n",
      "Optimization Iteration:    100, Training Accuracy:  96.9%\n",
      "Optimization Iteration:    200, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    299, Training Accuracy:  98.4%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Finding adversarial noise for target-class: 3\n",
      "Optimization Iteration:      0, Training Accuracy:  12.5%\n",
      "Optimization Iteration:    100, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    200, Training Accuracy: 100.0%\n",
      "Optimization Iteration:    299, Training Accuracy: 100.0%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Finding adversarial noise for target-class: 4\n",
      "Optimization Iteration:      0, Training Accuracy:  12.5%\n",
      "Optimization Iteration:    100, Training Accuracy:  87.5%\n",
      "Optimization Iteration:    200, Training Accuracy:  81.2%\n",
      "Optimization Iteration:    299, Training Accuracy:  92.2%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Finding adversarial noise for target-class: 5\n",
      "Optimization Iteration:      0, Training Accuracy:  15.6%\n",
      "Optimization Iteration:    100, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    200, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    299, Training Accuracy:  93.8%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Finding adversarial noise for target-class: 6\n",
      "Optimization Iteration:      0, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    100, Training Accuracy:  98.4%\n",
      "Optimization Iteration:    200, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    299, Training Accuracy:  98.4%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Finding adversarial noise for target-class: 7\n",
      "Optimization Iteration:      0, Training Accuracy:  14.1%\n",
      "Optimization Iteration:    100, Training Accuracy:  85.9%\n",
      "Optimization Iteration:    200, Training Accuracy:  85.9%\n",
      "Optimization Iteration:    299, Training Accuracy:  87.5%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Finding adversarial noise for target-class: 8\n",
      "Optimization Iteration:      0, Training Accuracy:  15.6%\n",
      "Optimization Iteration:    100, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    200, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    299, Training Accuracy:  93.8%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Finding adversarial noise for target-class: 9\n",
      "Optimization Iteration:      0, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    100, Training Accuracy:  87.5%\n",
      "Optimization Iteration:    200, Training Accuracy:  81.2%\n",
      "Optimization Iteration:    299, Training Accuracy:  85.9%\n",
      "Time usage: 0:00:01\n",
      "\n"
     ]
    }
   ],
   "source": [
    "all_noise = find_all_noise(num_iterations=300)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 绘制所有目标类型的对抗噪声"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个帮助函数用于在栅格中绘制所有目标类型（0到9）的对抗噪声。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_all_noise(all_noise):    \n",
    "    # Create figure with 10 sub-plots.\n",
    "    fig, axes = plt.subplots(2, 5)\n",
    "    fig.subplots_adjust(hspace=0.2, wspace=0.1)\n",
    "\n",
    "    # For each sub-plot.\n",
    "    for i, ax in enumerate(axes.flat):\n",
    "        # Get the adversarial noise for the i'th target-class.\n",
    "        noise = all_noise[i]\n",
    "        \n",
    "        # Plot the noise.\n",
    "        ax.imshow(noise,\n",
    "                  cmap='seismic', interpolation='nearest',\n",
    "                  vmin=-1.0, vmax=1.0)\n",
    "\n",
    "        # Show the classes as the label on the x-axis.\n",
    "        ax.set_xlabel(i)\n",
    "\n",
    "        # Remove ticks from the plot.\n",
    "        ax.set_xticks([])\n",
    "        ax.set_yticks([])\n",
    "    \n",
    "    # Ensure the plot is shown correctly with multiple plots\n",
    "    # in a single Notebook cell.\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f5d8c8c6b70>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_all_noise(all_noise)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "红色像素显示正噪声值，蓝色像素显示负噪声值。\n",
    "\n",
    "在其中一些噪声图像中，你可以看到数字的痕迹。例如，目标类型0的噪声显示了一个被蓝色包围的红圈。这说明会以圆形状将一些噪声添加到图像中，并抑制其他像素。这足以让MNIST数据集中的大部分图像被误分类成0。另外一个例子是3的噪声，图像的红色像素也显示了数字3的痕迹。但其他类别的噪声不太明显。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 对抗噪声的免疫"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在试着让神经网络对对抗噪声免疫。我们重新训练神经网络，使其忽略对抗噪声。这个过程可以重复多次。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 帮助函数创建了对对抗噪声免疫的神经网络\n",
    "\n",
    "这是使神经网络对对抗噪声免疫的帮助函数。首先运行优化来找到对抗噪声。接着执行常规优化使神经网络对该噪声免疫。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_immune(target_cls, num_iterations_adversary=500,\n",
    "                num_iterations_immune=200):\n",
    "\n",
    "    print(\"Target-class:\", target_cls)\n",
    "    print(\"Finding adversarial noise ...\")\n",
    "\n",
    "    # Find the adversarial noise.\n",
    "    optimize(num_iterations=num_iterations_adversary,\n",
    "             adversary_target_cls=target_cls)\n",
    "\n",
    "    # Newline.\n",
    "    print()\n",
    "    \n",
    "    # Print classification accuracy.\n",
    "    print_test_accuracy(show_example_errors=False,\n",
    "                        show_confusion_matrix=False)\n",
    "\n",
    "    # Newline.\n",
    "    print()\n",
    "\n",
    "    print(\"Making the neural network immune to the noise ...\")\n",
    "\n",
    "    # Try and make the neural network immune to this noise.\n",
    "    # Note that the adversarial noise has not been reset to zero\n",
    "    # so the x_noise variable still holds the noise.\n",
    "    # So we are training the neural network to ignore the noise.\n",
    "    optimize(num_iterations=num_iterations_immune)\n",
    "\n",
    "    # Newline.\n",
    "    print()\n",
    "    \n",
    "    # Print classification accuracy.\n",
    "    print_test_accuracy(show_example_errors=False,\n",
    "                        show_confusion_matrix=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 对目标类型3的噪声免疫\n",
    "\n",
    "首先尝试使神经网络对目标类型3的对抗噪声免疫。\n",
    "\n",
    "我们先找到导致神经网络误分类测试集上大多数图像的对抗噪声。接着执行常规优化，其变量经过微调从而忽略噪声，使得分类准确率再次达到95-97%。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Target-class: 3\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   1.6%\n",
      "Optimization Iteration:    100, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    200, Training Accuracy:  96.9%\n",
      "Optimization Iteration:    300, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    400, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    499, Training Accuracy:  96.9%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 13.3% (1326 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  12.5%\n",
      "Optimization Iteration:    100, Training Accuracy:  89.1%\n",
      "Optimization Iteration:    199, Training Accuracy:  95.3%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 93.3% (9327 / 10000)\n"
     ]
    }
   ],
   "source": [
    "make_immune(target_cls=3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在试着再次运行它。 现在更难为目标类别3找到对抗噪声。神经网络似乎已经变得对对抗噪声有些免疫。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Target-class: 3\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    100, Training Accuracy:  17.2%\n",
      "Optimization Iteration:    200, Training Accuracy:  32.8%\n",
      "Optimization Iteration:    300, Training Accuracy:  28.1%\n",
      "Optimization Iteration:    400, Training Accuracy:  21.9%\n",
      "Optimization Iteration:    499, Training Accuracy:  18.8%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 80.0% (8002 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  78.1%\n",
      "Optimization Iteration:    100, Training Accuracy:  90.6%\n",
      "Optimization Iteration:    199, Training Accuracy:  92.2%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 92.3% (9235 / 10000)\n"
     ]
    }
   ],
   "source": [
    "make_immune(target_cls=3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 对所有目标类型的噪声免疫\n",
    "\n",
    "现在，试着使神经网络对所有目标类型的噪声免疫。不幸的是，看起来并不太好。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Target-class: 0\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    100, Training Accuracy:  75.0%\n",
      "Optimization Iteration:    200, Training Accuracy:  76.6%\n",
      "Optimization Iteration:    300, Training Accuracy:  82.8%\n",
      "Optimization Iteration:    400, Training Accuracy:  85.9%\n",
      "Optimization Iteration:    499, Training Accuracy:  85.9%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 24.6% (2464 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  37.5%\n",
      "Optimization Iteration:    100, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    199, Training Accuracy:  98.4%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 93.9% (9387 / 10000)\n",
      "\n",
      "Target-class: 1\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   7.8%\n",
      "Optimization Iteration:    100, Training Accuracy:  62.5%\n",
      "Optimization Iteration:    200, Training Accuracy:  78.1%\n",
      "Optimization Iteration:    300, Training Accuracy:  65.6%\n",
      "Optimization Iteration:    400, Training Accuracy:  78.1%\n",
      "Optimization Iteration:    499, Training Accuracy:  71.9%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 32.6% (3260 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  45.3%\n",
      "Optimization Iteration:    100, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    199, Training Accuracy:  96.9%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 94.0% (9401 / 10000)\n",
      "\n",
      "Target-class: 2\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    100, Training Accuracy:  57.8%\n",
      "Optimization Iteration:    200, Training Accuracy:  81.2%\n",
      "Optimization Iteration:    300, Training Accuracy:  73.4%\n",
      "Optimization Iteration:    400, Training Accuracy:  87.5%\n",
      "Optimization Iteration:    499, Training Accuracy:  79.7%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 26.2% (2620 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  37.5%\n",
      "Optimization Iteration:    100, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    199, Training Accuracy:  95.3%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 93.8% (9380 / 10000)\n",
      "\n",
      "Target-class: 3\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  14.1%\n",
      "Optimization Iteration:    100, Training Accuracy:  50.0%\n",
      "Optimization Iteration:    200, Training Accuracy:  57.8%\n",
      "Optimization Iteration:    300, Training Accuracy:  59.4%\n",
      "Optimization Iteration:    400, Training Accuracy:  64.1%\n",
      "Optimization Iteration:    499, Training Accuracy:  59.4%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 46.3% (4631 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  46.9%\n",
      "Optimization Iteration:    100, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    199, Training Accuracy:  90.6%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 93.6% (9358 / 10000)\n",
      "\n",
      "Target-class: 4\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    100, Training Accuracy:  82.8%\n",
      "Optimization Iteration:    200, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    300, Training Accuracy:  90.6%\n",
      "Optimization Iteration:    400, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    499, Training Accuracy:  95.3%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 16.9% (1689 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  18.8%\n",
      "Optimization Iteration:    100, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    199, Training Accuracy:  92.2%\n",
      "Time usage: 0:00:00\n",
      "\n",
      "Accuracy on Test-Set: 93.3% (9332 / 10000)\n",
      "\n",
      "Target-class: 5\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  10.9%\n",
      "Optimization Iteration:    100, Training Accuracy:  65.6%\n",
      "Optimization Iteration:    200, Training Accuracy:  71.9%\n",
      "Optimization Iteration:    300, Training Accuracy:  78.1%\n",
      "Optimization Iteration:    400, Training Accuracy:  75.0%\n",
      "Optimization Iteration:    499, Training Accuracy:  76.6%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 26.4% (2638 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  29.7%\n",
      "Optimization Iteration:    100, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    199, Training Accuracy:  93.8%\n",
      "Time usage: 0:00:00\n",
      "\n",
      "Accuracy on Test-Set: 94.1% (9407 / 10000)\n",
      "\n",
      "Target-class: 6\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   6.2%\n",
      "Optimization Iteration:    100, Training Accuracy:  85.9%\n",
      "Optimization Iteration:    200, Training Accuracy:  90.6%\n",
      "Optimization Iteration:    300, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    400, Training Accuracy:  89.1%\n",
      "Optimization Iteration:    499, Training Accuracy:  89.1%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 15.8% (1584 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  17.2%\n",
      "Optimization Iteration:    100, Training Accuracy:  90.6%\n",
      "Optimization Iteration:    199, Training Accuracy:  93.8%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 93.8% (9385 / 10000)\n",
      "\n",
      "Target-class: 7\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  10.9%\n",
      "Optimization Iteration:    100, Training Accuracy:  96.9%\n",
      "Optimization Iteration:    200, Training Accuracy:  98.4%\n",
      "Optimization Iteration:    300, Training Accuracy:  96.9%\n",
      "Optimization Iteration:    400, Training Accuracy:  96.9%\n",
      "Optimization Iteration:    499, Training Accuracy:  98.4%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 13.2% (1319 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  23.4%\n",
      "Optimization Iteration:    100, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    199, Training Accuracy:  90.6%\n",
      "Time usage: 0:00:00\n",
      "\n",
      "Accuracy on Test-Set: 93.6% (9357 / 10000)\n",
      "\n",
      "Target-class: 8\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    100, Training Accuracy:  68.8%\n",
      "Optimization Iteration:    200, Training Accuracy:  73.4%\n",
      "Optimization Iteration:    300, Training Accuracy:  89.1%\n",
      "Optimization Iteration:    400, Training Accuracy:  89.1%\n",
      "Optimization Iteration:    499, Training Accuracy:  76.6%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 26.9% (2694 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  23.4%\n",
      "Optimization Iteration:    100, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    199, Training Accuracy:  95.3%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 94.5% (9452 / 10000)\n",
      "\n",
      "Target-class: 9\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    100, Training Accuracy:  48.4%\n",
      "Optimization Iteration:    200, Training Accuracy:  51.6%\n",
      "Optimization Iteration:    300, Training Accuracy:  51.6%\n",
      "Optimization Iteration:    400, Training Accuracy:  53.1%\n",
      "Optimization Iteration:    499, Training Accuracy:  50.0%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 46.6% (4657 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  50.0%\n",
      "Optimization Iteration:    100, Training Accuracy:  89.1%\n",
      "Optimization Iteration:    199, Training Accuracy:  93.8%\n",
      "Time usage: 0:00:00\n",
      "\n",
      "Accuracy on Test-Set: 94.6% (9462 / 10000)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "for i in range(10):\n",
    "    make_immune(target_cls=i)\n",
    "    \n",
    "    # Print newline.\n",
    "    print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 对所有目标类别免疫（执行两次）\n",
    "\n",
    "现在试着执行两次，使神经网络对所有目标类别的噪声免疫。不幸的是，结果也不太好。\n",
    "\n",
    "使神经网络免受一个对抗目标类型的影响，似乎使得它对另外一个目标类型失去了免疫。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Target-class: 0\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  10.9%\n",
      "Optimization Iteration:    100, Training Accuracy:  60.9%\n",
      "Optimization Iteration:    200, Training Accuracy:  76.6%\n",
      "Optimization Iteration:    300, Training Accuracy:  73.4%\n",
      "Optimization Iteration:    400, Training Accuracy:  57.8%\n",
      "Optimization Iteration:    499, Training Accuracy:  71.9%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 36.0% (3601 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  45.3%\n",
      "Optimization Iteration:    100, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    199, Training Accuracy:  93.8%\n",
      "Time usage: 0:00:00\n",
      "\n",
      "Accuracy on Test-Set: 94.7% (9474 / 10000)\n",
      "\n",
      "Target-class: 0\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  14.1%\n",
      "Optimization Iteration:    100, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    200, Training Accuracy:  12.5%\n",
      "Optimization Iteration:    300, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    400, Training Accuracy:   6.2%\n",
      "Optimization Iteration:    499, Training Accuracy:   6.2%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 93.3% (9334 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  87.5%\n",
      "Optimization Iteration:    100, Training Accuracy:  96.9%\n",
      "Optimization Iteration:    199, Training Accuracy:  98.4%\n",
      "Time usage: 0:00:00\n",
      "\n",
      "Accuracy on Test-Set: 95.2% (9524 / 10000)\n",
      "\n",
      "Target-class: 1\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   6.2%\n",
      "Optimization Iteration:    100, Training Accuracy:  53.1%\n",
      "Optimization Iteration:    200, Training Accuracy:  73.4%\n",
      "Optimization Iteration:    300, Training Accuracy:  73.4%\n",
      "Optimization Iteration:    400, Training Accuracy:  82.8%\n",
      "Optimization Iteration:    499, Training Accuracy:  81.2%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 25.4% (2543 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  21.9%\n",
      "Optimization Iteration:    100, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    199, Training Accuracy:  93.8%\n",
      "Time usage: 0:00:00\n",
      "\n",
      "Accuracy on Test-Set: 94.9% (9492 / 10000)\n",
      "\n",
      "Target-class: 1\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  12.5%\n",
      "Optimization Iteration:    100, Training Accuracy:  23.4%\n",
      "Optimization Iteration:    200, Training Accuracy:  10.9%\n",
      "Optimization Iteration:    300, Training Accuracy:  10.9%\n",
      "Optimization Iteration:    400, Training Accuracy:  10.9%\n",
      "Optimization Iteration:    499, Training Accuracy:   9.4%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 91.9% (9188 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    100, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    199, Training Accuracy:  89.1%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 95.5% (9545 / 10000)\n",
      "\n",
      "Target-class: 2\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   7.8%\n",
      "Optimization Iteration:    100, Training Accuracy:  62.5%\n",
      "Optimization Iteration:    200, Training Accuracy:  70.3%\n",
      "Optimization Iteration:    300, Training Accuracy:  78.1%\n",
      "Optimization Iteration:    400, Training Accuracy:  73.4%\n",
      "Optimization Iteration:    499, Training Accuracy:  71.9%\n",
      "Time usage: 0:00:02\n",
      "\n",
      "Accuracy on Test-Set: 34.7% (3474 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  51.6%\n",
      "Optimization Iteration:    100, Training Accuracy:  87.5%\n",
      "Optimization Iteration:    199, Training Accuracy:  95.3%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 95.2% (9520 / 10000)\n",
      "\n",
      "Target-class: 2\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  12.5%\n",
      "Optimization Iteration:    100, Training Accuracy:  15.6%\n",
      "Optimization Iteration:    200, Training Accuracy:  12.5%\n",
      "Optimization Iteration:    300, Training Accuracy:  18.8%\n",
      "Optimization Iteration:    400, Training Accuracy:  10.9%\n",
      "Optimization Iteration:    499, Training Accuracy:  14.1%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 90.5% (9051 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  87.5%\n",
      "Optimization Iteration:    100, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    199, Training Accuracy:  93.8%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 95.3% (9535 / 10000)\n",
      "\n",
      "Target-class: 3\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   7.8%\n",
      "Optimization Iteration:    100, Training Accuracy:  14.1%\n",
      "Optimization Iteration:    200, Training Accuracy:  43.8%\n",
      "Optimization Iteration:    300, Training Accuracy:  46.9%\n",
      "Optimization Iteration:    400, Training Accuracy:  48.4%\n",
      "Optimization Iteration:    499, Training Accuracy:  42.2%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 58.3% (5833 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  73.4%\n",
      "Optimization Iteration:    100, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    199, Training Accuracy:  95.3%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 95.4% (9537 / 10000)\n",
      "\n",
      "Target-class: 3\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  12.5%\n",
      "Optimization Iteration:    100, Training Accuracy:  10.9%\n",
      "Optimization Iteration:    200, Training Accuracy:  18.8%\n",
      "Optimization Iteration:    300, Training Accuracy:  10.9%\n",
      "Optimization Iteration:    400, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    499, Training Accuracy:   9.4%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 94.6% (9464 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    100, Training Accuracy:  96.9%\n",
      "Optimization Iteration:    199, Training Accuracy:  95.3%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 95.5% (9550 / 10000)\n",
      "\n",
      "Target-class: 4\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    100, Training Accuracy:  59.4%\n",
      "Optimization Iteration:    200, Training Accuracy:  73.4%\n",
      "Optimization Iteration:    300, Training Accuracy:  71.9%\n",
      "Optimization Iteration:    400, Training Accuracy:  81.2%\n",
      "Optimization Iteration:    499, Training Accuracy:  76.6%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 26.0% (2599 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  34.4%\n",
      "Optimization Iteration:    100, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    199, Training Accuracy:  92.2%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 95.5% (9545 / 10000)\n",
      "\n",
      "Target-class: 4\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  10.9%\n",
      "Optimization Iteration:    100, Training Accuracy:   7.8%\n",
      "Optimization Iteration:    200, Training Accuracy:   7.8%\n",
      "Optimization Iteration:    300, Training Accuracy:  15.6%\n",
      "Optimization Iteration:    400, Training Accuracy:  10.9%\n",
      "Optimization Iteration:    499, Training Accuracy:  10.9%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 92.2% (9225 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  85.9%\n",
      "Optimization Iteration:    100, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    199, Training Accuracy:  93.8%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 95.8% (9579 / 10000)\n",
      "\n",
      "Target-class: 5\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   6.2%\n",
      "Optimization Iteration:    100, Training Accuracy:  32.8%\n",
      "Optimization Iteration:    200, Training Accuracy:  67.2%\n",
      "Optimization Iteration:    300, Training Accuracy:  60.9%\n",
      "Optimization Iteration:    400, Training Accuracy:  76.6%\n",
      "Optimization Iteration:    499, Training Accuracy:  76.6%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 33.0% (3295 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  39.1%\n",
      "Optimization Iteration:    100, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    199, Training Accuracy:  93.8%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 95.3% (9533 / 10000)\n",
      "\n",
      "Target-class: 5\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  18.8%\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Optimization Iteration:    100, Training Accuracy:   1.6%\n",
      "Optimization Iteration:    200, Training Accuracy:  12.5%\n",
      "Optimization Iteration:    300, Training Accuracy:  14.1%\n",
      "Optimization Iteration:    400, Training Accuracy:  14.1%\n",
      "Optimization Iteration:    499, Training Accuracy:  15.6%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 91.9% (9194 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    100, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    199, Training Accuracy:  95.3%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 95.8% (9576 / 10000)\n",
      "\n",
      "Target-class: 6\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  14.1%\n",
      "Optimization Iteration:    100, Training Accuracy:  32.8%\n",
      "Optimization Iteration:    200, Training Accuracy:  67.2%\n",
      "Optimization Iteration:    300, Training Accuracy:  68.8%\n",
      "Optimization Iteration:    400, Training Accuracy:  68.8%\n",
      "Optimization Iteration:    499, Training Accuracy:  53.1%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 40.6% (4061 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  51.6%\n",
      "Optimization Iteration:    100, Training Accuracy:  92.2%\n",
      "Optimization Iteration:    199, Training Accuracy:  95.3%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 95.8% (9579 / 10000)\n",
      "\n",
      "Target-class: 6\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    100, Training Accuracy:   6.2%\n",
      "Optimization Iteration:    200, Training Accuracy:   4.7%\n",
      "Optimization Iteration:    300, Training Accuracy:  15.6%\n",
      "Optimization Iteration:    400, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    499, Training Accuracy:  20.3%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 94.0% (9396 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  93.8%\n",
      "Optimization Iteration:    100, Training Accuracy:  89.1%\n",
      "Optimization Iteration:    199, Training Accuracy:  95.3%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 96.0% (9602 / 10000)\n",
      "\n",
      "Target-class: 7\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  15.6%\n",
      "Optimization Iteration:    100, Training Accuracy:  59.4%\n",
      "Optimization Iteration:    200, Training Accuracy:  85.9%\n",
      "Optimization Iteration:    300, Training Accuracy:  87.5%\n",
      "Optimization Iteration:    400, Training Accuracy:  89.1%\n",
      "Optimization Iteration:    499, Training Accuracy:  92.2%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 17.5% (1751 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  17.2%\n",
      "Optimization Iteration:    100, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    199, Training Accuracy:  93.8%\n",
      "Time usage: 0:00:00\n",
      "\n",
      "Accuracy on Test-Set: 95.5% (9546 / 10000)\n",
      "\n",
      "Target-class: 7\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  10.9%\n",
      "Optimization Iteration:    100, Training Accuracy:  17.2%\n",
      "Optimization Iteration:    200, Training Accuracy:  17.2%\n",
      "Optimization Iteration:    300, Training Accuracy:  21.9%\n",
      "Optimization Iteration:    400, Training Accuracy:  18.8%\n",
      "Optimization Iteration:    499, Training Accuracy:  23.4%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 81.5% (8149 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  71.9%\n",
      "Optimization Iteration:    100, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    199, Training Accuracy:  98.4%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 95.5% (9550 / 10000)\n",
      "\n",
      "Target-class: 8\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  12.5%\n",
      "Optimization Iteration:    100, Training Accuracy:  26.6%\n",
      "Optimization Iteration:    200, Training Accuracy:  43.8%\n",
      "Optimization Iteration:    300, Training Accuracy:  60.9%\n",
      "Optimization Iteration:    400, Training Accuracy:  62.5%\n",
      "Optimization Iteration:    499, Training Accuracy:  64.1%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 44.9% (4493 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  45.3%\n",
      "Optimization Iteration:    100, Training Accuracy:  95.3%\n",
      "Optimization Iteration:    199, Training Accuracy:  95.3%\n",
      "Time usage: 0:00:00\n",
      "\n",
      "Accuracy on Test-Set: 96.2% (9616 / 10000)\n",
      "\n",
      "Target-class: 8\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   7.8%\n",
      "Optimization Iteration:    100, Training Accuracy:  12.5%\n",
      "Optimization Iteration:    200, Training Accuracy:  15.6%\n",
      "Optimization Iteration:    300, Training Accuracy:  15.6%\n",
      "Optimization Iteration:    400, Training Accuracy:   7.8%\n",
      "Optimization Iteration:    499, Training Accuracy:   9.4%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 95.5% (9555 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  96.9%\n",
      "Optimization Iteration:    100, Training Accuracy:  98.4%\n",
      "Optimization Iteration:    199, Training Accuracy:  95.3%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 96.5% (9650 / 10000)\n",
      "\n",
      "Target-class: 9\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   7.8%\n",
      "Optimization Iteration:    100, Training Accuracy:  28.1%\n",
      "Optimization Iteration:    200, Training Accuracy:  39.1%\n",
      "Optimization Iteration:    300, Training Accuracy:  42.2%\n",
      "Optimization Iteration:    400, Training Accuracy:  46.9%\n",
      "Optimization Iteration:    499, Training Accuracy:  48.4%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 64.1% (6415 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  68.8%\n",
      "Optimization Iteration:    100, Training Accuracy:  98.4%\n",
      "Optimization Iteration:    199, Training Accuracy:  96.9%\n",
      "Time usage: 0:00:00\n",
      "\n",
      "Accuracy on Test-Set: 96.3% (9629 / 10000)\n",
      "\n",
      "Target-class: 9\n",
      "Finding adversarial noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    100, Training Accuracy:   3.1%\n",
      "Optimization Iteration:    200, Training Accuracy:   3.1%\n",
      "Optimization Iteration:    300, Training Accuracy:  10.9%\n",
      "Optimization Iteration:    400, Training Accuracy:   9.4%\n",
      "Optimization Iteration:    499, Training Accuracy:   4.7%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 96.1% (9614 / 10000)\n",
      "\n",
      "Making the neural network immune to the noise ...\n",
      "Optimization Iteration:      0, Training Accuracy:  96.9%\n",
      "Optimization Iteration:    100, Training Accuracy: 100.0%\n",
      "Optimization Iteration:    199, Training Accuracy:  95.3%\n",
      "Time usage: 0:00:01\n",
      "\n",
      "Accuracy on Test-Set: 96.7% (9666 / 10000)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "for i in range(10):\n",
    "    make_immune(target_cls=i)\n",
    "    \n",
    "    # Print newline.\n",
    "    print()\n",
    "    \n",
    "    make_immune(target_cls=i)\n",
    "\n",
    "    # Print newline.\n",
    "    print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 绘制对抗噪声"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在我们已经对神经网络和对抗网络都进行了很多优化。让我们看看对抗噪声长什么样。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Noise:\n",
      "- Min: -0.35\n",
      "- Max: 0.35\n",
      "- Std: 0.27831247\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f5d8c9677f0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_noise()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有趣的是，相比优化之前的干净图像，神经网络在噪声图像上有更高的分类准确率。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy on Test-Set: 96.7% (9666 / 10000)\n",
      "Example errors:\n"
     ]
    },
    {
     "data": {
      "image/png": "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q001pbF6moqiKAEI5WmWlZWFHu63k5kBRo0aBcDnn38OwNSpU1PG8S79/PDDDwF3cvsrr7wCuJun2mNEIbuHYmumxYsXx5/16tULgK5du2b7pxQkUWjsJTkte3/CCScA8Je//AVIXCprl1HOnTs3a5qqcXDyrXGQcNaztIwfPx5wFz9A7WusnqaiKEoA8tanaUe1d+zYkTHcxRdfHL+2k9qT+7kyLe868MADAdcrtWE3b94MwBFHHBEPaz1ZS7oaccWKFfHrZcuWZQxbzPjV2M/f7t13380aZubMmYDbp221z2U5nmrsD78ajxw5Mmtamb5je1a53ZburrvuAuD6668HXK29zyw1rbF6moqiKAHIm6d58MEHA7BgwYKE535K+latWqV8nqmmsu+uueYaAO655x4gcXme3cTYHpuQjjPPPLNaukp1wmicTMeOHQF38+Fjjz02/s56llZTS7o+bz82qMb+8KvxY4895jvNVN/xU089BcBNN90EwMSJEwEoKYkVUR999FG1dGpLY/U0FUVRApA3T9Ov9+EdPbcMHDjQdz7JNchBBx0EwGWXXQYkjrrdfffdvtO1aD9XeqLwMJO55ZZbgMRRVDt6nszll18OwPDhw+PPcjn+RDVOj1+NvZvs2KOWL7nkEt/52Bait+8S3CODvfNBc9ErSo3V01QURQmAFpqKoigBqLFllOnwTj639OjRI2McP5269oz0q666Kv7stddeC2idUtOUlpYC/jTu378/kH06jJJ/mjVrFr/++OOPfcXxo/E//vEPAJYuXZqbYXlAPU1FUZQAROJpzpo1C4BTTz01/sxvx2ujRo2qPfPWWkFJznf58uXxa3ueUPJSLSU7YTQOi51aZJfUrVu3LuG99/REJXei0ti2FuzmGC1atMgaxy5ztEsf7RZub7/9dsL7uoB6moqiKAEI5WlWVVXFlz/lil2m5cUuf/rFL34BZK7tsvWL2GVZSm5EobGfM2f8aGyno5SXl4eyR0kkao3Hjh0LuNPHbrvtNiCzxl9//TXgngNmN2xJVT7UNuppKoqiBCCUp1lZWcm8efNC9W3ZEwYB3nnnHQB+/PFH3/Fbt24NuBsWJxMkLaU6UWgctu/zueeeA6BLly6AuxmLxW5OreRGvjTeY489AFi1ahUAnTt3ThvfzphJPpXUti509FxRFKWeEsrTbN68OX36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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f5d8c99fb70>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Confusion Matrix:\n",
      "[[ 966    0    0    0    0    1    5    1    5    2]\n",
      " [   0 1113    4    2    0    0    3    1   11    1]\n",
      " [   2    1  991    8    6    0    0    7   16    1]\n",
      " [   0    0    4  978    0   11    0    7    9    1]\n",
      " [   0    0    4    0  946    0    6    0    3   23]\n",
      " [   2    1    1    6    0  870    3    2    2    5]\n",
      " [   3    3    2    0    6   11  926    1    6    0]\n",
      " [   0    3   24    6    1    0    0  972    3   19]\n",
      " [   4    0    3    8    5    4    3    4  939    4]\n",
      " [   3    6    1   11    8    3    0    5    7  965]]\n"
     ]
    }
   ],
   "source": [
    "print_test_accuracy(show_example_errors=True,\n",
    "                    show_confusion_matrix=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 干净图像上的性能\n",
    "\n",
    "现在将对抗噪声重置为零，看看神经网络在干净图像上的表现。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "init_noise()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "相比噪声图像，神经网络在干净图像上表现的要更差一点。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy on Test-Set: 87.6% (8764 / 10000)\n",
      "Example errors:\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAU0AAAD5CAYAAACj3GcTAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xm8VfP+x/HXJyFCSqQbdVAariEeSYar7k0hUwiha4zrRsQls1/IlKGuIckQXV1DoYioTLmmlFKngWQs0kCSKer7+2Pv715rn3Gvs/fZwznv5+Ph0Tprf9da3+N71nd/1nd9B3POISIiqamT6wyIiBQSVZoiIhGo0hQRiUCVpohIBKo0RUQiUKUpIhKBKk0RkQhUaYqIRKBKU0QkgrrpHNy4cWNXVFSUoawUhpkzZ650zm2b63xki8q45lMZR5NWpVlUVMSMGTPSOUXBMbMvcp2HbFIZ13wq42j0eC4iEoEqTRGRCFRpiohEoEpTRCQCVZoiIhGo0hQRiUCVpohIBGn10xTJhe+//x6AL7/8stw0LVq0AGDo0KEA7LbbbgDsuuuuAOy5557VmUWpwRRpiohEoEhT8t7EiRMBeP755wF4/fXXAVi0aFG5x7Ru3RqAzz//HIDffvst6fMNGzZkOJdSWyjSFBGJIK8jzTVr1gBw+eWXAzBv3jwApk6dmkiz8cYbZz9jknGLFy8G4N577wVg5MiRic9++eUXAKIsN/3RRx9lMHciAUWaIiIR5GWk+dhjjwFw9dVXA6XfkvoIFGCbbbbJXsak2ixZsgSAYcOGpXWeNm3aAMHbcskfs2bNAuCaa64B4MUXX0x85p8izAyA448/HoAbb7wRgKZNmybSvvbaawB07doVgM0226w6s12KIk0RkQjyKtL00cZFF10EwMqVK4Hg28fr379/Yvuee+4BoFGjRtnIolSBL0cIIskDDzwQgEMPPRSATTbZBIAGDRoAsMUWWySOWbt2LQCHHHIIEESR++67LwB77bVXIq2POurXr5/h30Ki+v333wF44403ADj99NMB+Oabb4DS93V437hx44CgPMNPm773xOjRowHo06dPhnNeMUWaIiIRqNIUEYkgrx7Pb7/9dgBWrVpVYbonnngisT1p0iQgeGnkH939457kzk8//QRAt27dEvs+/PBDAMaPH5+Udr/99gOClwXhNWv8o9kOO+wAQJ06+q4vBB988AEQNKt4f/rTn4CgaQ1g8803T0rzxRdfJO0PN8ltuummQPLLoWzSX5+ISAQ5jzT9NwrAqFGjkj7zkyo0adIEgClTppQ6/ocffgCCKPWUU04BYPvtt898ZiUl69atA+Dkk08GgugS4MorrwTg4IMPLvPYslZFbN68eYZzKNWpuLgYgKOOOippvy/zm2++GYC999673HN8/fXXABx99NEArF69OvHZwIEDgaDLUbYp0hQRiSDnkebs2bMT277T+kEHHQQEXRV+/fVXAP773/8CwTcVwCeffALAsmXLgOCbybd1qitS9viuQTfddBMQTLCx7bbB8tKXXnopULoNS2qOwYMHA7BixQoAjjjiCADuuOMOAFq1alXpOXy06ttFw3w3tVxRpCkiEkHOI83wlF2+Y6vv3O7Vq1cPgDPPPBMIOr5CMNGDH4blIxi9Pc8+/0b8lltuAYKJgN98881EGt95XWqWs88+O7H91FNPAcEABf/3kEqE6TvE+6dJf1936dIlkaZz587pZzgNijRFRCLIeaT5+OOPl9r3wgsvANCzZ88yj5kxY0a55+vUqROQPAxPsuPtt99O+tkPb/T9K6XmCt+T/onRD2Vt165dpcf7CNNP5jFt2rSkc1177bWZy2yaFGmKiESQ80jzpJNOSmxPmDABgPfffx+AhQsXAjB37lwAnn32WSBYWAtg6623TtrnJ6/9+9//DqT2LSeZEW5rhqAHw3XXXZfY5/vuhSfZkNrJL0UCMHz4cCB4w+750UPt27fPWr4qo0hTRCQCVZoiIhHk/PE8PJzOd0eZM2cOAG3btgVKz7sXngDCrynjO9B+/PHHANx1110AjBgxojqyLWXwnZl9efnuZOHHc9/x+dxzzwWCOTG/+uorAFq2bAnAn//851Ln92tE+ck99IIpf/h7FYL797vvvgPKb4rxfy8QDJssea/7oZK+GS4fKNIUEYkg55FmeJjj2LFjAejVqxcQTMbhO7hecMEFANx6662JY3zH92OPPRYIOsW+/PLLQND5HWCXXXbJ/C8gCZdccglQujE/bP369UDwhOD/jWK77bYDgg7P4akCJTceeuihxPaPP/4IBF0HfeRZkeeeew6A//znP0DwUtE/keQTRZoiIhHkPNIM8+2b/lvGT9Dh2zOuv/56IIguw3yn2AULFgBB9yV/DMCjjz5aHdmWOD9c7oQTTgCCafp8x2UI1oHyEWdVLF++HAieTMIrT/rJqCW7witC+ola/Fo+JQej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EYlAlaaISASqNEVEIkiry5FIVa1eHVuKZquttgKgTh19f0th0F+qiEgEijQlJ44//ngA6tevD0Dfvn0BOOKII6rlesuXxxaSbNSoEQB16+pPX6pGkaaISAQF/3X7xRex0VB33XUXQGI42L333gvAbrvtlpuMSYX23ntvAIYMGQJA586pLNlTdcOGDQPg999/B+C2226r1utJzaVIU0QkgoKKND/++GMA7rnnnsS+0aNHA/DDDz8kpT300EMBmDhxYmLfV199BUCLFi0A2GOPPaovs1KhHXfcMSvXmTJlCgB33nknAL/99hugSDOXli5dCsCcOXMS+8aOHQsETwKff/45EJtMBOCWW25JpG3WrFkWclk+RZoiIhHkdaS5YcMGAObPnw9At27dAFi2bFmlx/pvs3Bb2Zo1sRVE99tvPwD+97//AeojmAvDhw/PynVee+01IIgwfVuqZI+/zwYPHgzA22+/DcCPP/6YSGNmZR771ltvAbDxxhsn9o0cORLIXQ8I1RYiIhGo0hQRiSAvH89XrFgBwN133w3ADTfcUG7arbfeGggevf0jvef3hy1cuDAprR7Ps6e4uBiAr7/+OivXmzp1atLP//d//5eV69ZmH3zwARD8v/Yv49atW5eUbtddd01sb7PNNgAccsghAHz00UdA8CJ31KhRibSnnXYaUP3d1Mqj2kJEJIK8jDSvuuoqAB544IGk/ZtssgkA//73vxP7dtppJwAGDRoEwLvvvlvuebfdNraO0oQJEwANpcuFd955ByjdRcwPp8wU/+LHd2HZbLPNADjooIMyep3azj+t+S5dEAxYWLlyJRDcZ6eccgoAxx13HAA9e/as9Pw9evQAYNKkSYl9c+fOBRRpiogUhJyHWuE2yF69egFBJOjbGn0n9AcffBAI2kgABgwYAATtlBXx3U18lyPJjrVr1ya277jjjqTPjjnmGADOOeecjF7T/w3Nnj076fy+DVwyw0eYAwcOTOxzzgHQpk0bAO6//34gc1G+HyrtuyxtueWWGTlvqhRpiohEkPNI00+0AfDss88mfea/qS6//HIADjzwQAB+/fXXlM8ffkPnv/Ekuy666KLEtn8r6lXX2+yHH364Ws4rMY8++igAl156aanPDjvsMCC4nzfddNPI5/dDpsNDLUte27/PyHaPCEWaIiIR5CzS9G81b7311nLT+HbK3r17J+33E8kC9O/fHwj64/lhV96ZZ56Z2PYTdUh2PPfcc0AwGUOYn4ihdevWGb2mfyv/7bffZvS8kuyzzz4DguGP++yzT+KzqkSYfoIOX27+DXxZ/Xn9Nf1E1tmmSFNEJIKcRZr+zbhvl4DSE3H4vnX+G+v8888H4OKLL06k8dO9lYxYO3XqBMA///nPTGZbUuBHYfmRXCX7ZEIQjdSrVy+j1/YRkH9r7p111lkZvY4kC4/2mTZtGhA8TfjJNnzPhaeeegqAcePGJY55//33gbL/Vko69dRTAWjVqlWaua4aRZoiIhGo0hQRiSBnj+cbbbQRAC+++GJinx+c74ddtW/fHgi6HnnhztJ++KTvhuQ7uvpuCX5dbckev/Kj74Qc5juz77777lnNk58QQjKjXbt2QPDo/eGHHyY+6969OxC8sPFNME2aNAGCdb18J/hw2lTsv//+SdfONkWaIiIR5Lxze3hYW58+fVI65umnn05sl+wQf+KJJwLJndolO15++WUArrzyyqT94QZ7v0qof9Lw0cZPP/1U7nl9ROG7qXl+ko+KohQf2e68886V/wKSshNOOAGAn3/+GYBrrrkm8dmSJUuS0vqnQB9h+pe/4S5DXbp0AYIXeX7Qix8MEV4X6OSTT87ML1FFijRFRCLIeaQZxXfffQeUnvQBoHnz5kAQyUj2+Uky/CS0np+mDeDGG29M+mz9+vUAjBgxotzz7rXXXgDMmjUraf+YMWMAOPLIIxP7Jk+enJTGP8lEaTOT1J1++ulJ/0KwJpDvsO4n3Ell9dc33ngDKD0BT3g1yi222KKq2c0IRZoiIhEUVKR5xBFHAMEkpGHXXnstEExULNkXbmsO+/LLLxPbVXkS8L0l/NOE7xHhJ7Xt0KFDIq1fKsXT4Ibs8xPr+H+juP3224HSwzNzNWSyLIo0RUQiKIhI89NPPwWCRbnCfPQZblOR3PBvUP0kKl54ohTfV6/k8hZ/+9vfgOSJH7yOHTsCwZvaxo0bA8FwPb8AHwR9Q30fX/WiKAz+jXvJ5WouueQSoGrTy1UXRZoiIhGo0hQRiSCvH8+XLl0KQNeuXYFgTRD/QgBKd5aW3Dn33HMB2HfffZP2N23aNLHt50LdfPPNI5+/YcOGST9369YNCLo6hfl1oBo0aBD5OpJ9Dz30EACrVq0CgnLzZZxPFGmKiESQ15Gm7yTtO8l64dnYw1Gn5JafaKWslznVKbxGjF+PKBzdSv7zA1c8P/Q2H1cPVaQpIhJBXkaa06dPB4IZmj3f7aBHjx5Zz5Pkr2233bbMbclv4enkHnnkESCYwMVP/5aPFGmKiESQV5Gmnx7Mt1GtXr066XP/9jTXA/ZFJH1XXHFFYtv3jPHrgnXu3DkneUqFIk0RkQjyKtIcOXIkAC+99FLS/u233x6ASZMmAdC2bdvsZkxEMmbOnDlAcD9DMEGHX3HWTx6djxRpiohEkFeRph/V4/tm+T53Z599NqC+dyI1QXiCFc9P6uInbslnijRFRCJQpSkiEkFePZ5fcMEFSf+KSM1z2mmnAcnrAPm5WP2a6flMkaaISAR5FWmKSM3n1w568803c5yTqlGkKSISgfkB8lU62GwF8EXmslMQWjjnas2sECrjmk9lHE1alaaISG2jx3MRkQhUaYqIRKBKU0QkggorTTPbxsxmx/9bZmZLQz9vUl2ZMrOLzWxe/L/+KaTva2Yr4vlaYGZnVnZMJed7zMx6pph2PzNbn2r6fJOrMo5fu66ZzTGz8SmkHRzK21wzOzzNa//PzNqnkO4kM5sf/1scnc41c0X3cUppU76PK+yn6ZxbBbSPn3QQsNY5d3uJixmxF0obUslcZeJ/yKcBHYA/gMlmNtE591klh45xzg0ws+2BYjN7zjm3MnTeus65PzKRx/A5gZuAKZk8bzblooxDLgaKgVTX873NOTfMzHYDXjOz7VzoTWamy9jM2gCXAPs751ab2XaZOnc26T6uNK+R7uMqPZ6bWcv4t+8YYB6wo5mtDn3e28wejG83MbNnzGyGmU03s06VnL4t8K5z7hfn3O/ANCDlyfWcc8uAz4Hm8ehktJm9BTwSj2zujOdjjpn1jeexjpkNN7OFZjYFaJzi5QYATwArK0tYaKq5jDGzFkA3YFTUvDnnigEDGsajifvMbDpwk5ltYWaPxPMxy8yOjF9vczMbG49gngbqpXCpc4C7nXOr49ddHjWv+Uz3cUKk+zidNs02wFDnXDtgaQXp7gKGOOc6ACcAvhD2NbMRZaSfC3Q2s0ZmVh84DNgx1UyZWUugBfBpKJ9dnXN9iN0Ey51zHYF9gPPMrDnQC9gJaAecAewfOt+NZlZqJbf4cYcDD6SatwJUXWUMMAy4FIjc583M9gd+dc75dV+bAp2ccwOBa4GX4mX8N+AOM6sHnA9875xrCwwG9gqdb5SV/ai+K9DWzN4ys3fMLP8HRken+zjifZzOMMrFzrkZKaQ7GGht8ZmZiUUHmznn3gPeK5nYOVdsZncCU4G1wCxgfQrXOcXMugC/AX3jj1MAE5xzv8bTdCd2E/SO/9wAaAUcBDwefzRZYmavh/JzVTnXGwYMdM5tCP1uNU21lLHF2o2+cs7NNrODI+TnUjM7HfgRODG0f2zosbI7cJiZXR7/uR7QnFgZDwFwzs0ys3n+YOfcGeVcry6wM9CZ2A38hpm1c86tiZDnfKf7OOJ9nE6l+VNoewOxxyUv/OhjQEfn3LpUT+ycGwmMBDCzIcAnKRw2xjk3oJJ8GtDPOfdKOIGZVWVu/Q7A2Pj/6MZAdzNb75x7vgrnylfVVcb7A8ea2VHx82xlZo86506r5LjbnHPDKsmnAT2dc4vDCar4xbYEeCPehrbYzBYDuxCrAGoK3ccR7+OMdDmK1+zfm1krM6tDctvFVOA8/0M5j0FJLN7gbmZFwFHE2hswswvN7Nw0svoy0M9iDb+YWWsz24xYe8uJ8TaRZsQiiwo555o754qcc0XAeOCcGlZhJslkGTvnBjrndoj/v+sDTPYVppkN8e2QVfQykHhTa2b+MXwacHJ8357An1M413igS/yY7YhVmJW9yChYuo9Tu48z2U/zMmK/zNvEvqG984AD4g2284GzodL2rvHxtOOBc0OPQ22BVWnk8X5gETDbzIqB+4hF2+OAL4H5xF5MvOMPKK8tpJbKZBmXZw9gWRp5vA6ob7FuSfOAQfH99wDbmNkC4BpC0WIFbZovAGvjv9NU4CL/UqgG031ciYIae25mLwBHZ7rLgeQHiz0jTXLOHZrrvEj1KfT7uKAqTRGRXNMwShGRCFRpiohEoEpTRCSCtNYIaty4sSsqKspQVgrDzJkzV9amWb1VxjWfyjiatCrNoqIiZsxIZTBBzWFmtWpZAJVxzacyjkaP5yIiEajSFBGJQJWmiEgEqjRFRCJQpSkiEoEqTRGRCFRpiohEoEpTRCQCVZoiIhGo0hQRiUCVpohIBGmNPa8uF198MQBDhw4FYO+99wZiY2QBvv7660Ta/fePrdK5116xpWD++te/AtC0aVMA6tTR90IhmDt3LgB33303ANOnT098tnDhQgAaNmwIwLJlyathXHrppYntIUOGVGs+pXpMnjwZgKuvvhqA999/H4DrrrsuaT/k/p5WjSIiEkFeRZpTp04F4NlnnwXgmWeeAWDTTTcFYMKECQCsXbs2ccyoUaOS/vWfderUCYAxY8Yk0u64Y8pr1UuW+CjytNNiq/fOmlX+6rglI0xv4sSJie3zzostmNiiRYtMZVGqyUsvvZTYPumkkwD44YcfgGDJ5UGDBgFwySWXJNJuvvnmWcph2RRpiohEkFeR5sMPPwxAs2bNADjmmOS133v0qHwFzjvuuAOAnXfeGYBGjRplMouSId9//z0AJ5xwAhC0aVbEl+V3332XtH/BggWJ7dGjRwNwzTXXZCSfknklyx6CJ8S//OUvQFAHPPHEEwCsX78+m1mskCJNEZEIVGmKiESQV4/ns2fPBmDfffet8jn+9a9/ZSo7Uo38y77yHsv/8Y9/JLYHDBgAwFZbbQXADTfcAMCIESNKHTdv3ryM5lMyxy+p0a9fPyD5ha5venv66aeBoMuRfzwfPnx4Iu1ll11W/ZmtgCJNEZEIch5p/vbbb6W2d9ttt1xlR7LEdy8raZ999gHg/PPPT+xr06YNAD///DMA7777brnn/fjjjzOVRckQ37XID0JYtGgRAPfdd18ije9y5LsXlvTpp59WZxYjUaQpIhJBziPNpUuXJrb98EjfwVVqrosuugiAJ598EoANGzYAQWf3jz76KJH2scceA6C4uBgI2r7LUrKbmuTOq6++CkCvXr0AWLduHRB0VA+3W//yyy8ADB48GAiG03rLly+v3sxGoEhTRCSCnEeavhM6wNFHHw3AbbfdBkD//v0B2HbbbSs9z8CBAwHo1q1b0r+Sn3zbZefOnQF47bXXAPjxxx+BIDqJ6qCDDspA7iQdq1evBuDkk08GgrZo30597LHHAnDmmWcmjnnhhRcAWLFiRZnnvOqqq6ons1WgSFNEJIKcR5phrVq1AuDXX38F4LnnngPgrLPOqvRY3wfMOQco0iwUU6ZMAYJ+eb6da86cOSmfo2PHjoltRZq553swrFmzJmn/tGnTALj//vsB+P333ys910477QTA7rvvnskspkWRpohIBHkVafqJhD3/Rq0iY8eOBYK3rmeffXbmMybVZqONNgKCqfyuuOIKIHkqsHAPi7Ctt94aCNq+IZhSTHLHR/5+IvDPPvsMCJ4e/MiusiJNX35du3YFghFC5fXfzAVFmiIiEajSFBGJIK8ez3v27AnAAQccAMAtt9wCwBlnnAFA/fr1Sx3jXyR88803QLCOkBQmP7Bh5cqVlab1Lwr9HIySX/xKCyUHI/iXOiWb4yBYH8x3O8xHijRFRCLIq0jTrzLnZ3S+8MILgWCFQb9eiO+SBEFXFSlsfqikL/PwRC6ef0nQu3dvIHgikfzkJ94pOQFPnz59SqX10//dfPPN1Z+xNCnSFBGJIK9EQcerAAAGoElEQVQiTe+CCy4Agu4G119/PRCshe0H/kPQhlnRJA6Svx588EEgWNOnrAjz+OOPB2C//fYDgsk+pLD41WUff/zxUp/5p4e6dfOySkqiSFNEJIK8rtbHjx8PwEMPPQTAF198ASSvNOinkpLC8uijjwJwzjnnAMHwV893jAYYOXIkEHRml8Lk16f3Ze2HTQO0bNkyJ3mqCkWaIiIR5HWk2bBhQyB5SF1Je+65Z7ayIxngI8yrr74aKB1heqeffnpiWxFmYfNDnMeNGwcEQyJvv/32RBq/pn0hUKQpIhKBKk0RkQjy+vFcaobwCpF+Bu7yZi7yM7r74XRS+IYOHQoE65zvsMMOABx55JE5y1M6FGmKiERQ8JFmeetnS/4Iz3FaWYTp14pp3Lhx9WdMqpUf7jx58uSk/f4lYKFSpCkiEkHBR5p+GGWTJk2Asqebktzwk3D44a9l2XLLLYFgwoZUVh6VwrB+/XogGJTiFfra9Io0RUQiKPhI0w+/WrVqFQDFxcUAdOjQIWd5qu0WL14MQL9+/YDkqfxK6tu3LxCskS01x7333lvm/kWLFgEwatSoxL4uXboAySuL5itFmiIiERR8pOn5KaXKWhJDsmuXXXYBoFmzZkAwjC6se/fuAFx22WXZy5hkVY8ePQC4/PLLk/YfeOCBADRo0CCx7+ijj85extKkSFNEJIKCjzR9vz8/uUfbtm1zmR0J8T0bwpFmvXr1gGDiDt/rQWqedu3aAXDccccBwaTivt0yPK1j69ats5y7qlOkKSISgSpNEZEICv7x/Nprr036V/LHpEmTcp0FySG/uuzYsWNznJPMUqQpIhKBKk0RkQhUaYqIRGDlrdGS0sFmK4AvKk1Ys7RwztWaWSVUxjWfyjiatCpNEZHaRo/nIiIRqNIUEYmgwkrTzLYxs9nx/5aZ2dLQz5tUV6bM7GIzmxf/r38K6fua2Yp4vhaY2ZlpXv8xM+tZSZqDzeyH0P+Pq9K5Zq6ojCtM09DMXjCzD+P5PDWda+aKyjiltPuZ2fpU0lfYud05twpoHz/pIGCtc+72cBozM2JtoxtSyVxlzKw9cBrQAfgDmGxmE51zn1Vy6Bjn3AAz2x4oNrPnnHMrQ+et65z7IxN5DHnNOZdSoeQrlXGF+gOznXOHm1kTYKGZ/bca/o6qlcq40rzWBW4CpqSSvkqP52bW0szmm9kYYB6wo5mtDn3e28wejG83MbNnzGyGmU03s06VnL4t8K5z7hfn3O/ANCDl+fGdc8uAz4HmZjbYzEab2VvAI2ZW18zujOdjjpn1jeexjpkNN7OFZjYFqPWreqmMY5cCtoxvbwGsBNanms98pzJOGAA8Qax8K5VOm2YbYKhzrh1Q9hKDMXcBQ5xzHYATAF8I+5rZiDLSzwU6m1kjM6sPHAbsmGqmzKwl0AL4NJTPrs65PsA5wHLnXEdgH+A8M2sO9AJ2AtoBZwD7h853o5n1KOdyB1rs0e1FM2uXah4LSG0v438D7c3sa+BDoL+red1NanUZx487HHgg1bylM/Z8sXNuRgrpDgZax6J/ABqa2WbOufeA90omds4Vm9mdwFRgLTCL1L7dTzGzLsBvQF/n3Or4NSc45/x6C92BtmbWO/5zA6AVcBDwePzRZImZvR7KT3ltle8DRc65tWZ2JPAMsYKtSWp7GfcApgOdgV2Bl8xsd+fc2hTyWihqexkPAwY65zaEfrcKpVNp/hTa3gCEr1gvtG1AR+fculRP7JwbCYwEMLMhwCcpHDbGOTegknwa0M8590o4gZlFXh7POfdDaPt5M7vPzLZ2zq2u6LgCU6vLmFi0MigeXX5kZl8Rqzw/qMK58lVtL+MOwNh4hdkY6G5m651zz5d3QEa6HMVr9u/NrJWZ1SG57WIqcJ7/wWINxBUys+3i/xYBRxFrb8DMLjSzc9PI6stAP4s1/GJmrc1sM2LtLSfG20SaEYssKsvj9qHtTsAfNazCTFIbyxj4EugaP09ToCVQ2YuMglUby9g519w5V+ScKwLGA+dUVGFCZvtpXkbsl3kbWBLafx5wQLzBdj5wNlTYFgIwPp52PHCuc25NfH9bYFUaebwfWATMNrNi4D5i0fY4YjfIfGAU8I4/oIL2rt4W60oxGxgKnJhGvgpFbSvjQcTa5eYQe7N6iXPu+zTyVghqWxlHVlDDKM3sBeDoQuvyIalTGdd8hV7GBVVpiojkmoZRiohEoEpTRCQCVZoiIhGo0hQRiUCVpohIBKo0RUQiUKUpIhLB/wPEyf8AOtlOfQAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f5dcc037c50>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Confusion Matrix:\n",
      "[[ 948    0    3    0    0    1   27    1    0    0]\n",
      " [   0 1110    5    1    0    0   19    0    0    0]\n",
      " [   5    1 1022    0    0    0    0    0    4    0]\n",
      " [   0    1   22  955    1   23    1    5    2    0]\n",
      " [   0    3    2    0  941    0   36    0    0    0]\n",
      " [   1    0    1    1    0  869   20    0    0    0]\n",
      " [   1    1    1    0    1    1  953    0    0    0]\n",
      " [   7   32   77    2   43    4    1  855    7    0]\n",
      " [  13    7   45    8    7   39  107    1  747    0]\n",
      " [  11   18    6   10  465   79   32    8   16  364]]\n"
     ]
    }
   ],
   "source": [
    "print_test_accuracy(show_example_errors=True,\n",
    "                    show_confusion_matrix=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 关闭TensorFlow会话"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在我们已经用TensorFlow完成了任务，关闭session，释放资源。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "# This has been commented out in case you want to modify and experiment\n",
    "# with the Notebook without having to restart it.\n",
    "# session.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 讨论"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在上面的实验中可以看到，我们能够使神经网络对单个目标类别的对抗噪声免疫。这使得不可能找到引起误分类到目标类型的对抗噪声。但是，显然也不可能使神经网络同时对所有目标类别免疫。可能用其他方法能够做到这一点。\n",
    "\n",
    "一种建议是对不同目标类型进行交叉的免疫训练，而不是依次对每个目标类型进行完全的优化。对上面的代码做些小修改就能做到这一点。\n",
    "\n",
    "另一个建议是设置两层神经网络，共11个网络。第一层网络用来对输入图像进行分类。这个网络没有对对抗噪声免疫。然后根据第一层的预测类型选择第二层的另一个网络。第二层中的网络对各自目标类型的对抗噪声免疫。因此，一个对抗样本可能糊弄第一层的网络，但第二层中的网络会免于特定目标类型噪声的影响。\n",
    "\n",
    "这可能使用了类型数量比较少的情况，但如果数量很大就变得不可行，比如ImageNet有1000个类别，这样我们在第二层中需要训练1000个神经网络，这并不实际。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结\n",
    "\n",
    "这篇教程展示了如何找到MNIST数据集手写数字的对抗噪声。 每个目标类别都找到了一个单一的噪声模式，它导致几乎所有的输入图像都被误分类为目标类别。\n",
    "\n",
    "MNIST数据集的噪声模式对人眼清晰可见。但可能在高分辨率图像上（比如ImageNet数据集）工作的大型神经网络可以找到更细微的噪声模式。\n",
    "\n",
    "本教程也尝试了使神经网络免受对抗噪声影响的方法。 这对单个目标类别有效，但所测试的方法无法使神经网络同时对所有对抗目标类别免疫。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 练习\n",
    "\n",
    "下面使一些可能会让你提升TensorFlow技能的一些建议练习。为了学习如何更合适地使用TensorFlow，实践经验是很重要的。\n",
    "\n",
    "在你对这个Notebook进行修改之前，可能需要先备份一下。\n",
    "\n",
    "* 尝试为对抗噪声使用更少或更多的优化迭代数。\n",
    "* 教程#11只需少于30次的迭代次数就能找到对抗噪声，相比之下为什么这篇教程需要更多迭代？\n",
    "* 尝试设置不同的`noise_limit` 和 `noise_l2_weight`。这会如何影响对抗噪声以及分类准确率？\n",
    "* 试着为目标类型1寻找对抗噪声。它是否适用于目标类型3？\n",
    "* 你能找到一个更好的方法，使得神经网络对对抗噪声免疫吗？\n",
    "* 神经网络是否可以对单个图像产生的对抗噪声免疫，就像教程 #11 中所做的那样？\n",
    "* 尝试用不同的配置创建另一个神经网络。一个网络上的对抗噪声对另一个网络有效吗？\n",
    "* 用CIFAR-10数据集代替MNIST。你可以复用教程 #06 中的一些代码。\n",
    "* 你会如何找到Inception模型和ImageNet数据集的对抗噪声？\n",
    "* 向朋友解释程序如何工作。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## License (MIT)\n",
    "\n",
    "Copyright (c) 2016 by [Magnus Erik Hvass Pedersen](http://www.hvass-labs.org/)\n",
    "\n",
    "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n",
    "\n",
    "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n",
    "\n",
    "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
